pub const std = @import("std");

pub const ENTITY_COUNT = 5;

pub const Position = @import("component/position.zig").Position;
pub const PositionStorage = @import("component/position.zig").PositionStorage(ENTITY_COUNT);
pub const Velocity = @import("component/velocity.zig").Velocity;
pub const VelocityStorage = @import("component/velocity.zig").VelocityStorage(ENTITY_COUNT);

const active_components = [_]type{
    Position, 
    Velocity
};

const Entity = @Type(std.builtin.TypeInfo{.Int = .{
    .signedness = .unsigned,
    .bits = active_components.len,
}});

pub const EntityStorage = struct {
    const Self = @This();

    entities: [ENTITY_COUNT]Entity,

    pub const Iterator = struct {
        const Self = @This();
        entities: []const Entity,
        blueprint: Entity,
        index: usize,

        pub fn next(self: *@This()) ?usize {
            const b = self.blueprint;
            for (self.entities[self.index..]) |e, i| {
                const result = b & e;
                if (result == b) {
                    return i;
                }
            }
            return null;
        }

        pub fn reset(self: *@This()) void {
            self.index = 0;
        }
    };

    pub fn init() Self {
        return Self {
            .entities = [_]Entity{0} ** ENTITY_COUNT,
        };
    }

    fn getIndex(comptime lit: @Type(.EnumLiteral)) usize {
        inline for (active_components) |C, i| {
            if (std.mem.eql(u8, @typeName(C), @tagName(lit))) {
                return i;
            }
        }

        @compileError("Invalid enum literal");
    }

    pub fn iter(self: Self, comptime conditions: anytype) Iterator {
        var blueprint: Entity = 0;
        inline for (conditions) |cond| {
            blueprint |= 1 << comptime getIndex(cond);
        }

        return Iterator {
            .blueprint = blueprint,
            .entities = &self.entities,
            .index = 0,
        };
    }
};
